home *** CD-ROM | disk | FTP | other *** search
- ;; $Id: highmem.inc,v 1.4 2004/12/17 06:42:01 hpa Exp $
- ;; -----------------------------------------------------------------------
- ;;
- ;; Copyright 1994-2004 H. Peter Anvin - All Rights Reserved
- ;;
- ;; This program is free software; you can redistribute it and/or modify
- ;; it under the terms of the GNU General Public License as published by
- ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
- ;; Boston MA 02111-1307, USA; either version 2 of the License, or
- ;; (at your option) any later version; incorporated herein by reference.
- ;;
- ;; -----------------------------------------------------------------------
-
- ;;
- ;; highmem.inc
- ;;
- ;; Probe for the size of high memory. This can be overridden by a
- ;; mem= command on the command line while booting a new kernel.
- ;;
-
- section .text
-
- ;
- ; This is set up as a subroutine; it will set up the global variable
- ; HighMemSize. All registers are preserved. Assumes DS == CS.
- ;
- highmemsize:
- push es
- pushad
-
- ;
- ; First, try INT 15:E820 (get BIOS memory map)
- ;
- get_e820:
- xor ebx,ebx ; Start with first record
- mov dword [E820Max],-(1 << 20) ; Max amount of high memory
- mov dword [E820Mem],ebx ; Detected amount of high memory
- mov es,bx ; Need ES = DS = 0 for now
- jmp short .do_e820 ; Skip "at end" check first time!
- .int_loop: and ebx,ebx ; If we're back at beginning...
- jz .e820_done ; ... we're done
- .do_e820: mov eax,0000E820h
- mov edx,534D4150h ; "SMAP" backwards
- xor ecx,ecx
- mov cl,20 ; ECX <- 20
- mov di,E820Buf
- int 15h
- jnc .no_carry
- ; If carry, ebx == 0 means error, ebx != 0 means we're done
- and ebx,ebx
- jnz .e820_done
- jmp no_e820
- .no_carry:
- cmp eax,534D4150h
- jne no_e820
- ;
- ; Look for a memory block starting at <= 1 MB and continuing upward
- ;
- cmp dword [E820Buf+4], byte 0
- ja .int_loop ; Start >= 4 GB?
- mov edx, (1 << 20)
- sub edx, [E820Buf]
- jnb .ram_range ; Start >= 1 MB?
- ; If we get here, it starts > 1 MB but < 4 GB; if this is a
- ; *non*-memory range, remember this as unusable; some BIOSes
- ; get the length of primary RAM wrong!
- cmp dword [E820Buf+16], byte 1
- je .int_loop ; If it's memory, don't worry about it
- neg edx ; This means what for memory limit?
- cmp edx,[E820Max] ; Better or worse
- jnb .int_loop
- mov [E820Max],edx
- jmp .int_loop
-
- .ram_range:
- stc
- sbb eax,eax ; eax <- 0xFFFFFFFF
- cmp dword [E820Buf+12], byte 0
- ja .huge ; Size >= 4 GB
- mov eax, [E820Buf+8]
- .huge: sub eax, edx ; Adjust size to start at 1 MB
- jbe .int_loop ; Completely below 1 MB?
-
- ; Now EAX contains the size of memory 1 MB...up
- cmp dword [E820Buf+16], byte 1
- jne .int_loop ; High memory isn't usable memory!!!!
-
- ; We're good!
- mov [E820Mem],eax
- jmp .int_loop ; Still need to add low 1 MB
-
- .e820_done:
- mov eax,[E820Mem]
- and eax,eax
- jz no_e820 ; Nothing found by E820?
- cmp eax,[E820Max] ; Make sure we're not limited
- jna got_highmem_add1mb
- mov eax,[E820Max]
- jmp got_highmem_add1mb
-
- ;
- ; INT 15:E820 failed. Try INT 15:E801.
- ;
- no_e820:
- mov ax,0e801h ; Query high memory (semi-recent)
- int 15h
- jc no_e801
- cmp ax,3c00h
- ja no_e801 ; > 3C00h something's wrong with this call
- jb e801_hole ; If memory hole we can only use low part
-
- mov ax,bx
- shl eax,16 ; 64K chunks
- add eax,(16 << 20) ; Add first 16M
- jmp short got_highmem
-
- ;
- ; INT 15:E801 failed. Try INT 15:88.
- ;
- no_e801:
- mov ah,88h ; Query high memory (oldest)
- int 15h
- cmp ax,14*1024 ; Don't trust memory >15M
- jna e801_hole
- mov ax,14*1024
- e801_hole:
- and eax,0ffffh
- shl eax,10 ; Convert from kilobytes
- got_highmem_add1mb:
- add eax,(1 << 20) ; First megabyte
- got_highmem:
- %if HIGHMEM_SLOP != 0
- sub eax,HIGHMEM_SLOP
- %endif
- mov [HighMemSize],eax
- popad
- pop es
- ret ; Done!
-
- section .bss
- alignb 4
- E820Buf resd 5 ; INT 15:E820 data buffer
- E820Mem resd 1 ; Memory detected by E820
- E820Max resd 1 ; Is E820 memory capped?
- HighMemSize resd 1 ; End of memory pointer (bytes)
-